Skip to content

feat: OCG-backed long-term agent memory with human good/bad feedback links#423

Open
NicholasDCole wants to merge 1 commit into
mainfrom
feature/add_memory
Open

feat: OCG-backed long-term agent memory with human good/bad feedback links#423
NicholasDCole wants to merge 1 commit into
mainfrom
feature/add_memory

Conversation

@NicholasDCole

Copy link
Copy Markdown

Summary

Ports the Python-SDK side of the OCG-backed agent memory feature from agentspan-ai/agentspan#298 onto this repo's main. Server-side compiler support (inlining the memory retrieval/distill/save/feedback steps on the deployed/webhook path) lives in conductor-oss/conductor (agentspan-server).

What it does

  • OCGMemoryStore (src/conductor/ai/agents/ocg_memory.py, new) — a synchronous MemoryStore HTTP adapter over the OCG BFF: POST /api/v1/memories/search, POST /api/v1/memories, POST /api/v1/memories/{key}/feedback-links (mints signed good/bad capability URLs), bearer-token auth. Plus MemorySummary / build_memory_summarizer (internal conversation-distiller sub-agent) and FeedbackEvent.
  • Agent paramssemantic_memory, memory_summary_model, feedback_sink on Agent.
  • Runtime pre-run — relevant agent/user-scoped memories are retrieved and injected into a COPY of the agent's instructions (the shared agent is never mutated).
  • Runtime post-run — the conversation is distilled by a summarizer sub-agent (structured {summary, facts, tags} output; reuses the agent's model unless memory_summary_model is set) and saved as a conversation:<session> memory. Best-effort and recursion-guarded — memory never fails the primary run.
  • Human-only feedback — the runtime hands a FeedbackEvent (distilled summary + signed good/bad URLs) to feedback_sink for out-of-band delivery; the URLs are never surfaced to the agent's LLM. The compiled path registers an {agent}_feedback_sink worker mirroring run()'s delivery.
  • Serializer — emits longTermMemory {ocgUrl, credential, agent, user, scope, maxResults, summaryModel} and feedbackSink {taskName} on the agent-config JSON. credential is a server-resolvable secret NAME (default OCG_PUBLIC_KEY), never the raw client token.

Path adaptations from the upstream PR

  • Module path conductor.ai.agents.* is unchanged, so ocg_memory.py ports verbatim.
  • Spawn-safe worker entries: this repo has since moved system workers from nested closures to picklable entry classes in runtime/_worker_entries.py (with probe_spawn_safety). The upstream PR's nested feedback_sink_worker closure was therefore ported as a new FeedbackSinkEntry class, registered via _register_feedback_sink_worker following the StopWhenEntry/GateEntry pattern.
  • Example renumbered 118_ocg_memory.pyexamples/agents/120_ocg_memory.py (118 and 119 are taken here) and moved into examples/agents/.
  • Tests land under tests/unit/ai/ (this repo's layout) instead of tests/unit/.

Testing

  • pytest tests/unit/ai/test_ocg_memory_store.py tests/unit/ai/test_config_serializer.py — 36 passed.
  • Full pytest tests/unit — 2493 passed, 34 skipped, 0 failed (Python 3.12 venv + pyyaml/pydantic).
  • python -c "import conductor.ai.agents" still succeeds without the agents extras installed (httpx is a base dep; pydantic import in ocg_memory.py is guarded).

🤖 Generated with Claude Code

…links

Port of the SDK side of agentspan-ai/agentspan#298.

- OCGMemoryStore: synchronous MemoryStore HTTP adapter over the OCG BFF
  (search / save / delete / list, plus minting signed good/bad capability
  feedback URLs). Bearer-token auth held client-side.
- Agent params: semantic_memory, memory_summary_model, feedback_sink.
- AgentRuntime pre-run hook injects relevant agent/user-scoped memories
  into a COPY of the agent's instructions; post-run hook distills the
  conversation via an internal summarizer sub-agent (structured
  MemorySummary output, reuses the agent's model unless
  memory_summary_model is set) and saves it as conversation:<session>.
  Both hooks are best-effort and recursion-guarded — memory never fails
  the primary run.
- Feedback is human-only: the runtime hands a FeedbackEvent (distilled
  summary + signed good/bad URLs) to feedback_sink for out-of-band
  delivery; the URLs are never shown to the agent's LLM. The compiled
  path registers a spawn-safe {agent}_feedback_sink worker
  (FeedbackSinkEntry) mirroring run()'s delivery.
- Serializer emits longTermMemory {ocgUrl, credential, agent, user,
  scope, maxResults, summaryModel} and feedbackSink {taskName} so the
  server-side compiler can inline memory steps on the deployed/webhook
  path. credential is a server-resolvable secret NAME, never the raw
  client token.
- Example examples/agents/120_ocg_memory.py (renumbered from upstream
  118, which is taken here) and unit tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.89362% with 59 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/conductor/ai/agents/ocg_memory.py 77.98% 24 Missing ⚠️
src/conductor/ai/agents/runtime/runtime.py 74.72% 23 Missing ⚠️
src/conductor/ai/agents/runtime/_worker_entries.py 21.42% 11 Missing ⚠️
src/conductor/ai/agents/config_serializer.py 94.44% 1 Missing ⚠️
Files with missing lines Coverage Δ
src/conductor/ai/agents/agent.py 66.01% <100.00%> (+0.28%) ⬆️
src/conductor/ai/agents/config_serializer.py 65.46% <94.44%> (+2.69%) ⬆️
src/conductor/ai/agents/runtime/_worker_entries.py 65.51% <21.42%> (+0.76%) ⬆️
src/conductor/ai/agents/runtime/runtime.py 51.08% <74.72%> (-3.20%) ⬇️
src/conductor/ai/agents/ocg_memory.py 77.98% <77.98%> (ø)

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant